package net.cs.rm;

import java.awt.image.BufferedImage;
import java.io.*;
import java.util.*;
import java.util.Map.Entry;

import javax.imageio.ImageIO;  

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import dao.hb.NBase;
import dao.hb.NImage;

import psd.model.Psd;

import net.bat.db.BaseDAOImpl;
import net.bat.upload.uploadServlet;
import net.coobird.thumbnailator.Thumbnails;

 class KeywordFileFilter implements FileFilter {

	  private String keyword;

	  public KeywordFileFilter(String keyword) {
	    this.keyword = keyword;
	  }

	  public boolean accept(File pathname) {
		if(pathname.isDirectory()){
			return true;
		}
		String fn = pathname.getName().toLowerCase();
		//不会重复抽点
		if(fn.startsWith(ImgUtil.pref_m)||fn.startsWith(ImgUtil.pref_s)){
			return false;
		}else return fn.endsWith(keyword);
	  }
}
public class ImgUtil {
	public final static String 	PATH_UPLOAD;
	static{
		if(File.separatorChar=='/'){
			PATH_UPLOAD ="/Users/chen4w/upload/";
		}else{
			PATH_UPLOAD="d:/upload/";
		}
	}
	final static Logger logger = LoggerFactory.getLogger(ImgUtil.class);
	static public String pref_l = "l_";
	static public String pref_m = "m_";
	static public String pref_s = "s_";
	static public String INDEX_FN = "map.inc";
	static public final String charsetName = "UTF-8"; 
	BaseDAOImpl dao=null;
	String fpath;
	String fpath_inc;
	NBase rnb;

	ImgUtil(String path,BaseDAOImpl dao){
		this.fpath=path;
		this.dao = dao;
		if(path.endsWith(File.separator)){
			this.fpath_inc = path+INDEX_FN;
		}else{
			this.fpath_inc = path+File.separator+INDEX_FN;
		}
	}

	private static final FileFilter IMAGES_FILTER = new FileFilter() {		 
	  public boolean accept(File f) {
	   return f.isDirectory() || f.getName().matches("^.*?\\.(jpg|png)$");
	  }
	};

	//索引文件加载 图片路径-菜品条目id
	HashMap<String,Integer> pmap=null;
	//图片路径-菜品名称
	HashMap<String,String> nmap=null;
	//菜品名-菜品条目
	HashMap<String,NBase> dmap = null;
	
	//匹配规则
	boolean match(String src,String target){		
		return (target.indexOf(src)!=-1);
	}
	
	void match(){
		Iterator<Entry<String,Integer>> iter = pmap.entrySet().iterator(); 
		while (iter.hasNext()) { 
			Entry<String,Integer> entry = iter.next(); 
			if(entry.getValue()!=null){
				continue;
			}
			String key =entry.getKey();
			NBase nb = match(key);
			if(nb!=null){
				entry.setValue(nb.getId());
				nmap.put(key, nb.getTitle());
			}
		} 	
	}
	void loadNode(int rid){
		this.rnb = (NBase)dao.get("from NBase where itype=1 and id=?", rid);
		dmap = new HashMap<String,NBase>();
		List ls=dao.find("from NBase where itype=4 and pnid=?", new Object[]{rid});
		int len= ls.size();
		for(int i=0; i<len; i++){
			NBase nb = (NBase)ls.get(i);
			dmap.put(nb.getTitle(), nb);
		}
	}
	//匹配规则
	NBase match(String name){		
		Iterator<Entry<String,NBase>> iter = dmap.entrySet().iterator(); 
		while (iter.hasNext()) { 
			Entry<String,NBase> entry = iter.next(); 
			if(match(entry.getKey(),name)){
				return entry.getValue();
			}
		} 	
		return null;
	}
	/**
	 * 建立索引map,如果存在索引文件,先加载之
	 * @param fpath
	 * @throws Exception 
	 */
	public void buildPMap() throws Exception{
		pmap = new HashMap<String,Integer>();
		nmap = new HashMap<String,String>();
		loadIndex(this.fpath_inc);
		appendPMap(new File(fpath));
		System.out.println("append dir size:"+pmap.size());
	}
	private void appendPMap(File dir){
		File[] fs = dir.listFiles(IMAGES_FILTER);
		for(int i=0; i<fs.length; i++){
			if(fs[i].isDirectory()){
				appendPMap(fs[i]);
			}else{
				String key =fs[i].getPath();
				nmap.put(key, null);
				pmap.put(key, null);
			}
		}
	}
	public void loadIndex(String fn_inc)
		throws Exception{
		File finc = new File(fn_inc);
		if(!finc.exists()){
			System.out.println("not find index file");
			return;
		}
		System.out.println("find index file:"+fn_inc);
		InputStreamReader insReader = new InputStreamReader(
				new FileInputStream(finc), charsetName);
		BufferedReader bufReader = new BufferedReader(insReader);
		String line = new String();
		while ((line = bufReader.readLine()) != null) {
			if(line.trim().equals("")){
				continue;
			}
			String[] pid = line.split("	");
			String key = pid[0];
			if(pid.length==3){
				pmap.put(key, Integer.parseInt(pid[1]));
				nmap.put(key, pid[2]);
			}else{
				pmap.put(key, null);
				nmap.put(key,null);
			}
		}
		bufReader.close();
		insReader.close();		
		System.out.println("index file size:"+pmap.size());
	}
	public void outputImg(Integer rid){
		if(rid==null){
			rid = this.rnb.getId();
		}
		List ls = dao.find("from NBase A,NBase B, NImage C where B.pnid=A.id and C.nid=B.id and B.vid=C.id and A.pnid=?",new Object[]{rid});
		int len = ls.size();
		for(int i=0; i<len; i++){
			Object[] os = (Object[])ls.get(i);
			NBase n0 = (NBase)os[0];
			NBase n1 = (NBase)os[1];
			NImage n2 = (NImage)os[2];
			System.out.println("menu id:"+n0.getId());
			System.out.println("menu title:"+n0.getTitle());
			System.out.println("img id:"+n1.getId());
			System.out.println("img title:"+n2.getTitle());
			System.out.println("img uri:"+n2.getUri());
			System.out.println("\n");
		}
	}
	public void savetoDB(){
		int uid = rnb.getUid();
		Iterator<Entry<String,Integer>> iter = pmap.entrySet().iterator(); 
		while (iter.hasNext()) { 
			Entry<String,Integer> entry = iter.next(); 
			Integer nid = entry.getValue();
			String path = entry.getKey();
			if(nid==null || nid<0){
				continue;
			}
			String[] str = getTitleByPath(path);
			if(str==null){
				continue;
			}
			String img_title = str[0];
			String img_type = str[1];
			
			List ls = dao.find("from NBase A,NImage B where A.itype="
					+JSonOut.TYPE_NODE_IMAGE
					+" and A.pnid=? and A.title=? and A.vid=B.id", new Object[]{nid,img_title});
			NBase nimg=null;
			for(int i=0; i<ls.size(); i++){
				Object[] co = (Object[])ls.get(i);
				if(bSame((NImage)co[1],path)){
					nimg=(NBase)co[0];
					break;
				}
			}
			
			//找该菜品节点下重名的图像节点
			if(nimg==null){ 
				//重名被加入的
				if(ls.size()!=0){
					System.out.println("append same img name["+path+"] to node["+nid+"]");
				}
				nimg = new NBase();
				nimg.setTitle(img_title);
				nimg.setPnid(nid);
				nimg.setUid(uid);
				nimg.setItype(JSonOut.TYPE_NODE_IMAGE);
				nimg.setLanguage(rnb.getLanguage());
				dao.save(nimg);
				NImage img = new NImage();
				img.setNid(nimg.getId());
				img.setTitle(nimg.getTitle());
				dao.save(img);
				String uri = "["+uid+"_"+"image]"+img.getId()+img_type;
				img.setUri(uri);
				System.out.println("copy ["+path+"] to ["+nid+"-"+uri+"]" );
				copyImg(path,uri);
				dao.update(img);
				nimg.setVid(img.getId());
				dao.update(nimg);
			}else{
				//如果已经存在同名影像,将此图片标志为重复
				entry.setValue(-nimg.getId());
				System.out.println("same img:"+path);
			}
		} 	
	}
	/**
	 * 比较判断是否相同图片，更加合理的是采用图片相似度判断
	 * @param ni
	 * @param path
	 * @return
	 * @throws IOException 
	 */
	private boolean bSame(NImage ni,String path) {
		String uri = ni.getUri();
		if(uri==null){
			return false;
		}
		String fn1 = uploadServlet.getURIPath(uri);
		File f1 = new File(fn1);
		File f2 = new File(path);
		if(f1.length() != f2.length()){
			return false;
		}
		try {
			BufferedImage bi1 = ImageIO.read(f1);
			BufferedImage bi2 = ImageIO.read(f2);
			if(bi1.getWidth()!=bi2.getWidth() || bi1.getHeight()!=bi2.getHeight()){
				return false;
			}else{
				return true;
			}
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return true;
	}
	static private void copyFile(File fi,File fo){
		int length=2097152;
	  	FileInputStream in;
		try {
			in = new FileInputStream(fi);
			  FileOutputStream out=new FileOutputStream(fo);
			  byte[] buffer=new byte[length];
			  int len = 0;
			  while(len!=-1){
			   len=in.read(buffer);
			   if(len!=-1){
			    out.write(buffer,0,len);
			   }
			  }		
		    in.close();
		    out.flush();
		    out.close();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	static private void copyImg(String pathFrom,String uri){
		String pathTo=uploadServlet.getURIPath(uri);
		copyFile(new File(pathFrom),new File(pathTo));
	}
	private String[] getTitleByPath(String path){
		int len = path.length();
		int ce=-1,cb=-1;
		for(int i=len-1;i>=0; i--){
			char ch = path.charAt(i);
			if(ce==-1 && Msyy.isChe(ch) && ch!='元'){
				ce=i;
			}
			if(ce!=-1 && !Msyy.isChe(ch)){
				cb=i;
				break;
			}
		}
		if(ce!=-1 && cb!=-1){
			String[] str=new String[2];
			str[0]=path.substring(cb+1, ce+1);
			str[1]=path.substring(ce+1);
			return str;
		}
		return null;
	}
	public void savetoIndex() 
			throws IOException{
		File finc = new File(this.fpath_inc);
		OutputStreamWriter osw = new OutputStreamWriter(
				new FileOutputStream(finc), charsetName);
		Iterator<Entry<String,Integer>> iter = pmap.entrySet().iterator(); 
		int cout1=0;
		int cout2=0;
		while (iter.hasNext()) { 
			Entry<String,Integer> entry = iter.next(); 
			Integer nid = entry.getValue();
			String key = entry.getKey();
			if(nid==null){
				cout1++;
				osw.write(key+"\n");
			}else{
				cout2++;
				osw.write(key+"	"+entry.getValue()
						+"	"+nmap.get(key)+"\n");
			}
		} 	
		osw.close();	
		System.out.println("not matched:"+cout1+" macthed:"+cout2);
	}
	static public void getthumb(String fmt, File f, String pref, int wh) throws IOException{
		String fn = f.getName();
		if(!f.exists()){
			return;
		}
		if(f.isFile()){
			BufferedImage bi = ImageIO.read(f);
			File fo = new File(f.getParent()+File.separator+pref+f.getName());
			if(bi.getWidth()<wh && bi.getHeight()<wh){
				copyFile(f,fo);
			}else{
				System.out.println("getthumb file:"+fn);
				Thumbnails.of(f).size(wh, wh).outputFormat(fmt).toFile(fo);
			}
		}else{
			System.out.println("getthumb dir:"+fn);
			File[] fs = f.listFiles(new KeywordFileFilter(fmt));
			for(int i=0; i<fs.length; i++){
				getthumb(fmt,fs[i],pref,wh);
			}
		}
		
	}
	static public String getfn(int sno,String fmt){
		if(sno<10){
			return "00"+sno+fmt;
		}else if(sno < 100){
			return "0"+sno+fmt;
		}else{
			return sno+fmt;
		}
	}
	static public int addImgPath(String fmt,String path_src,String path_target,Integer sno){
		File fsrc = new File(path_src);
		if(!fsrc.exists()){
			return sno;
		}
		File[] fs = fsrc.listFiles(new KeywordFileFilter(fmt));
		for(int i=0; i<fs.length; i++){
			fs[i].renameTo(new File(path_target,getfn(sno++,fmt)));
		}
		return sno;
	}
	static public void psd2jpg(String fpath_psd) throws IOException{
		File fin = new File(fpath_psd);
		Psd fi = new Psd(fin);
		int pos = fpath_psd.lastIndexOf('.');
		String fpath_out = fpath_psd.subSequence(0, pos)+"png";
		ImageIO.write(fi.getImage(), "png", new File(fpath_out));		
	}
	static public void tif2jpg(String ftif,String fout){
		
	}
    public static void main(String[] args) {
/*    	Integer sno=1;
    	sno = addImgPath(".jpg","/Users/chen4w/Downloads/chrome/photo (1)","/Users/chen4w/Documents/phs",sno);
    	sno = addImgPath(".jpg","/Users/chen4w/Downloads/chrome/photo (11)","/Users/chen4w/Documents/phs",sno);
    	sno = addImgPath(".jpg","/Users/chen4w/Downloads/chrome/photo (7)","/Users/chen4w/Documents/phs",sno);
    	sno = addImgPath(".jpg","/Users/chen4w/Downloads/chrome/photo (6)","/Users/chen4w/Documents/phs",sno);
*/		try {
		getthumb("jpg",new File("/Users/chen4w/Documents/phs"),"s_",128);
		getthumb("jpg",new File("/Users/chen4w/Documents/phs"),"m_",400);
		getthumb("jpg",new File("/Users/chen4w/Documents/phs"),"l_",1280);
	
	if(true)
		return;

		//psd2jpg("/Users/chen4w/Downloads/0001阿公里脊.psd");
		//通过spring加载数据库访问类
	    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("/applicationContext-common.xml");	        
	    BaseDAOImpl dao = (BaseDAOImpl) applicationContext.getBean("BaseDAOImpl");
	    logger.info("Spring context initialized.");
	    //设置本地上传文件路径
	    uploadServlet.setPath(PATH_UPLOAD);
	    ///////////设置你的图片库根路径
	    ImgUtil util = new ImgUtil("/Users/chen4w/Downloads/chrome/photo_lt1024",dao);
	    //加载根目录下的索引文件并递归遍历子目录,生成图片路径索引
	    util.buildPMap();
	    /////////////指定餐馆id,从数据库加载菜品名称
	    util.loadNode(33725);
	    //以菜品名称在图片索引中进行匹配,更新匹配结果到图片索引
	    util.match();
	    //将匹配结果写入数据库,如果存在同文件名,同文件大小、等宽高的图片,忽略之
	    util.savetoDB();
	    //将新的匹配结果写入索引文件 map.inc
	    util.savetoIndex();
	    //输出包含图片的菜品
	    //util.outputImg(null);
	
	} catch (Exception e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	}    	
   }
}
